#ifndef OCL_COMM_H
#define OCL_COMM_H

#include <iostream>
#include <stdexcept>
#include <string>

#ifndef __APPLE__
	#include <windows.h>
#endif

#ifndef OCL_NAME_MAX
#define OCL_NAME_MAX 1024
#endif

namespace ocl
{
inline void dprintf(const char *fmt, ...)
{
    const int MAXLOGMSG = 4096;
	char buffer[MAXLOGMSG];
	va_list marker;

	va_start(marker, fmt);
#ifndef __APPLE__
    vsnprintf_s(buffer, MAXLOGMSG, MAXLOGMSG, fmt, marker);
	OutputDebugStringA(buffer);
#else
    vsnprintf(buffer, 1024, fmt, marker);
	printf("%s", buffer);
#endif
	va_end (marker);	
}
const char errmap[65][45] = {
    "CL_SUCCESS"                        ,"CL_DEVICE_NOT_FOUND"             ,"CL_DEVICE_NOT_AVAILABLE",
    "CL_COMPILER_NOT_AVAILABLE"         ,"CL_MEM_OBJECT_ALLOCATION_FAILURE","CL_OUT_OF_RESOURCES",
    "CL_OUT_OF_HOST_MEMORY"             ,"CL_PROFILING_INFO_NOT_AVAILABLE" ,"CL_MEM_COPY_OVERLAP",
    "CL_IMAGE_FORMAT_MISMATCH"          ,"CL_IMAGE_FORMAT_NOT_SUPPORTED"   ,"CL_BUILD_PROGRAM_FAILURE",
    "CL_MAP_FAILURE"                    ,"CL_MISALIGNED_SUB_BUFFER_OFFSET" ,"CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST",
    "N/A"                               ,"N/A"                             ,"N/A",
    "N/A"                               ,"N/A"                             ,"N/A",
    "N/A"                               ,"N/A"                             ,"N/A",
    "N/A"                               ,"N/A"                             ,"N/A",
    "N/A"                               ,"N/A"                             ,"N/A",
    "CL_INVALID_VALUE"                  ,"CL_INVALID_DEVICE_TYPE"          ,"CL_INVALID_PLATFORM",
    "CL_INVALID_DEVICE"                 ,"CL_INVALID_CONTEXT"              ,"CL_INVALID_QUEUE_PROPERTIES",
    "CL_INVALID_COMMAND_QUEUE"          ,"CL_INVALID_HOST_PTR"             ,"CL_INVALID_MEM_OBJECT",
    "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR","CL_INVALID_IMAGE_SIZE"           ,"CL_INVALID_SAMPLER",
    "CL_INVALID_BINARY"                 ,"CL_INVALID_BUILD_OPTIONS"        ,"CL_INVALID_PROGRAM",
    "CL_INVALID_PROGRAM_EXECUTABLE"     ,"CL_INVALID_KERNEL_NAME"          ,"CL_INVALID_KERNEL_DEFINITION",
    "CL_INVALID_KERNEL"                 ,"CL_INVALID_ARG_INDEX"            ,"CL_INVALID_ARG_VALUE",
    "CL_INVALID_ARG_SIZE"               ,"CL_INVALID_KERNEL_ARGS"          ,"CL_INVALID_WORK_DIMENSION",
    "CL_INVALID_WORK_GROUP_SIZE"        ,"CL_INVALID_WORK_ITEM_SIZE"       ,"CL_INVALID_GLOBAL_OFFSET",
    "CL_INVALID_EVENT_WAIT_LIST"        ,"CL_INVALID_EVENT"                ,"CL_INVALID_OPERATION",
    "CL_INVALID_GL_OBJECT"              ,"CL_INVALID_BUFFER_SIZE"          ,"CL_INVALID_MIP_LEVEL",
    "CL_INVALID_GLOBAL_WORK_SIZE"       ,"CL_INVALID_PROPERTY"
};

inline void logErr(int error)
{
    if (error)
    {
        error = error < 0  ? error : -error;
        error = error < 65 ? error : 15;
        dprintf("[ERROR](num,expr)=(%d, %s)\n", error, errmap[-error]);
    }
}

#define OCL_CHKRET(_expr)                                           \
{                                                                   \
    cl_int _err = _expr;                                            \
    if (_err != CL_SUCCESS)                                         \
    {                                                               \
        dprintf("[ERROR](num,expr)=(%d, %s)\n", (int)_err, #_expr); \
        logErr(_err);                                               \
        throw std::runtime_error(#_expr);                           \
    }                                                               \
};

}
#endif
